home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / readers / skim-0.8 / skim-0 / skim-0.8.4 / StandardIO.c < prev    next >
C/C++ Source or Header  |  1996-02-18  |  11KB  |  507 lines

  1. /*
  2.  * NAME
  3.  *   StandardIO.c
  4.  * DESCRIPTION
  5.  *   The class StandardIO is an adapter for the standard I/O of ANSI C (class
  6.  *   FILE). StandardIO adds implicit error handling and support for variable
  7.  *   length buffers (VarBuf). If a StandardIO operation returns, it was 
  8.  *   successful.
  9.  * COPYRIGHT
  10.  *   Skim - Off-line news reading package optimized for slow lines.
  11.  *   Copyright (C) 1996  Rene W.J. Pijlman
  12.  *
  13.  *   This program is free software; you can redistribute it and/or modify
  14.  *   it under the terms of the GNU General Public License as published by
  15.  *   the Free Software Foundation; either version 2 of the License, or
  16.  *   (at your option) any later version.
  17.  * 
  18.  *   This program is distributed in the hope that it will be useful,
  19.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  *   GNU General Public License for more details.
  22.  * 
  23.  *   You should have received a copy of the GNU General Public License
  24.  *   along with this program; if not, write to the Free Software
  25.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  * VERSION
  27.  *   Skim version 0.8.4.
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <assert.h>
  33. #include <sys/stat.h>
  34. #include <unistd.h>
  35. #include <stdlib.h>
  36.  
  37. #include "MemAlloc.h"
  38. #include "VarBuf.h"
  39. #include "StandardIO.h"
  40.  
  41. #define CLASS_NAME "StandardIO"
  42. #include "CheckForDebris.h"
  43.  
  44. struct _StandardIO {
  45.     VarBuf FileName;
  46.     FILE * File;
  47.     Boolean OpenForRead;
  48.     Boolean OpenForWrite;
  49. };
  50.  
  51. #ifndef NDEBUG
  52. static Boolean ClassInvariant( StandardIO This )
  53. {
  54.     assert( This != NULL );
  55.  
  56.     if ( This->File == NULL )
  57.     {
  58.         assert( This->FileName == NULL );
  59.         assert( !This->OpenForRead );
  60.         assert( !This->OpenForWrite );
  61.     }
  62.     else
  63.     {
  64.         assert( This->FileName != NULL );
  65.         assert( This->OpenForRead || This->OpenForWrite );
  66.     }
  67.  
  68.     return This != NULL &&
  69.            ((This->File == NULL) == (This->FileName == NULL)) &&
  70.            (This->File == NULL || This->OpenForRead || This->OpenForWrite) &&
  71.            (This->File != NULL || (!This->OpenForRead && !This->OpenForWrite));
  72. }
  73. #endif
  74.  
  75. struct _StandardIO _StandardInput;
  76. struct _StandardIO _StandardOutput;
  77. struct _StandardIO _StandardError;
  78.  
  79. StandardIO StandardInput = &_StandardInput;
  80. StandardIO StandardOutput = &_StandardOutput;
  81. StandardIO StandardError = &_StandardError;
  82.  
  83. static Boolean ClassInitialized = False;
  84.  
  85. static void ClassDestruct( int ExitStatus, void * ClientData )
  86. {
  87.     SIODestroy( StandardInput );
  88.     StandardInput = NULL;
  89.  
  90.     SIODestroy( StandardOutput );
  91.     StandardOutput = NULL;
  92.  
  93.     SIODestroy( StandardError );
  94.     StandardError = NULL;
  95. }
  96.  
  97. static void InitializeClass( void )
  98. {
  99.     VarBuf StandardInputFileName = VBCreate();
  100.     VarBuf StandardOutputFileName = VBCreate();
  101.     VarBuf StandardErrorFileName = VBCreate();
  102.  
  103.     VBAppendString( StandardInputFileName, "<standard input>" );
  104.     VBAppendString( StandardOutputFileName, "<standard output>" );
  105.     VBAppendString( StandardErrorFileName, "<standard error>" );
  106.  
  107.     StandardInput->File = stdin;
  108.     StandardInput->FileName = StandardInputFileName;
  109.     StandardInput->OpenForRead = True;
  110.     StandardInput->OpenForWrite = False;
  111.  
  112.     StandardOutput->File = stdout;
  113.     StandardOutput->FileName = StandardOutputFileName;
  114.     StandardOutput->OpenForRead = False;
  115.     StandardOutput->OpenForWrite = True;
  116.  
  117.     StandardError->File = stderr;
  118.     StandardError->FileName = StandardErrorFileName;
  119.     StandardError->OpenForRead = False;
  120.     StandardError->OpenForWrite = True;
  121.  
  122.     if ( on_exit( ClassDestruct, NULL ) != 0 )
  123.     {
  124.     fprintf( stderr, "Cannot register function with on_exit()\n" );
  125.     exit( EXIT_FAILURE );
  126.     }
  127.  
  128.     ClassInitialized = True;
  129. }
  130.  
  131. /*
  132.  * Must be used in all non-static functions, since operations can be
  133.  * performed on the globals StandardInput, StandardOutput, StandardError
  134.  * without a call to SIOCreate().
  135.  */
  136. #define INITIALIZE_CLASS { if ( !ClassInitialized ) InitializeClass(); }
  137.  
  138.  
  139. StandardIO SIOCreate( void )
  140. {
  141.     StandardIO New;
  142.  
  143.     INITIALIZE_CLASS;
  144.  
  145.     New = MemAlloc( sizeof(struct _StandardIO) );
  146.  
  147.     New->FileName = NULL;
  148.     New->File = NULL;
  149.     New->OpenForRead = False;
  150.     New->OpenForWrite = False;
  151.  
  152.     assert( ClassInvariant( New ) );
  153.  
  154.     IncrementObjectCount();
  155.  
  156.     return New;
  157. }
  158.  
  159.  
  160. void SIODestroy( StandardIO This )
  161. {
  162.     INITIALIZE_CLASS;
  163.  
  164.     if ( This != NULL )
  165.     {
  166.     assert( ClassInvariant(This) );
  167.  
  168.     SIOFileClose( This );
  169.  
  170.     if ( This != StandardInput &&
  171.          This != StandardOutput &&
  172.          This != StandardError )
  173.     {
  174.         MemFree(This);
  175.  
  176.         DecrementObjectCount();
  177.     }
  178.     }
  179. }
  180.  
  181.  
  182. Boolean SIOFileExists( const char * FileName )
  183. {
  184.     struct stat stat_buf;
  185.  
  186.     INITIALIZE_CLASS;
  187.  
  188.     return stat( FileName, &stat_buf ) == 0;
  189. }
  190.  
  191.  
  192. void SIORemove( const char * FileName )
  193. {
  194.     assert( SIOFileExists( FileName ) );
  195.  
  196.     if ( remove(FileName) != 0 )
  197.     {
  198.     fprintf( stderr, "Cannot remove " );
  199.     perror( FileName );
  200.     exit( EXIT_FAILURE );
  201.     }
  202.  
  203.     assert( !SIOFileExists( FileName ) );
  204. }
  205.  
  206.  
  207. static void SIOFileOpen_(
  208.     StandardIO This,
  209.     const char * FileName,
  210.     OpenMode Mode,
  211.     Boolean OpenFile,
  212.     int FileDescriptor )
  213. {
  214.     const char * ModeString = NULL;
  215.  
  216.     assert( ClassInvariant(This) );
  217.     assert( !This->OpenForRead && !This->OpenForWrite );
  218.     assert( FileName != NULL && strlen(FileName) > 0 );
  219.     assert( Mode != OpenModeWrite || !SIOFileExists(FileName) );
  220.  
  221.     switch ( Mode )
  222.     {
  223.         case OpenModeRead:
  224.         case OpenModeReadIgnore:
  225.             ModeString = "r";
  226.             This->OpenForRead = True;
  227.             break;
  228.     case OpenModeWrite:
  229.     case OpenModeWriteDiscardOld:
  230.         ModeString = "w";
  231.         This->OpenForWrite = True;
  232.         break;
  233.     case OpenModeAppend:
  234.         ModeString = "a";
  235.         This->OpenForWrite = True;
  236.         break;
  237.     case OpenModeReadAndWriteDiscardOld:
  238.         ModeString = "r+";
  239.             This->OpenForRead = True;
  240.         This->OpenForWrite = True;
  241.         break;
  242.     default:
  243.         assert( False );
  244.         break;
  245.     }
  246.  
  247.     This->File = OpenFile ?  fopen( FileName, ModeString ) :
  248.                              fdopen( FileDescriptor, ModeString );
  249.  
  250.     if ( This->File != NULL )
  251.     {
  252.     assert( This->FileName == NULL );
  253.     This->FileName = VBCreate();
  254.     VBAppendString( This->FileName, FileName );
  255.     }
  256.     else if ( Mode == OpenModeReadIgnore && errno == ENOENT )
  257.     {
  258.     This->OpenForRead = False;
  259.     This->OpenForWrite = False;
  260.     }
  261.     else
  262.     {
  263.     fprintf( stderr, "Cannot open " );
  264.     perror( FileName );
  265.     exit( EXIT_FAILURE );
  266.     }
  267.  
  268.     assert( ClassInvariant(This) );
  269.     assert( ( Mode == OpenModeReadIgnore && errno == ENOENT ) ||
  270.             This->OpenForRead || This->OpenForWrite );
  271. }
  272.  
  273.  
  274. void SIOFileOpen(
  275.     StandardIO This,
  276.     const char * FileName,
  277.     OpenMode Mode )
  278. {
  279.     INITIALIZE_CLASS;
  280.  
  281.     assert( ClassInvariant(This) );
  282.  
  283.     SIOFileOpen_( This, FileName, Mode, True, 0 );
  284. }
  285.  
  286.  
  287. void SIOFileOpenFileDescriptorVB(
  288.     StandardIO This,
  289.     int FileDescriptor,
  290.     VarBuf PseudoFileName,
  291.     OpenMode Mode )
  292. {
  293.     INITIALIZE_CLASS;
  294.  
  295.     assert( ClassInvariant(This) );
  296.  
  297.     SIOFileOpen_(This, VBAsString(PseudoFileName), Mode, False, FileDescriptor);
  298. }
  299.  
  300.  
  301. void SIOFileOpenVB(
  302.     StandardIO This,
  303.     VarBuf FileName,
  304.     OpenMode Mode )
  305. {
  306.     INITIALIZE_CLASS;
  307.  
  308.     assert( ClassInvariant(This) );
  309.  
  310.     SIOFileOpen( This, VBAsString(FileName), Mode );
  311. }
  312.  
  313.  
  314. void SIOFileClose( StandardIO This )
  315. {
  316.     INITIALIZE_CLASS;
  317.  
  318.     assert( ClassInvariant(This) );
  319.  
  320.     if ( This->File != NULL )
  321.     {
  322.     if ( This != StandardInput &&
  323.          This != StandardOutput &&
  324.          This != StandardError )
  325.     {
  326.         if ( fclose(This->File) == EOF )
  327.         {
  328.         fprintf( stderr, "Cannot close " );
  329.         perror( VBAsString(This->FileName) );
  330.         exit( EXIT_FAILURE );
  331.         }
  332.     }
  333.     This->File = NULL;
  334.  
  335.     VBDestroy( This->FileName );
  336.     This->FileName = NULL;
  337.  
  338.     This->OpenForRead = False;
  339.     This->OpenForWrite = False;
  340.     }
  341.  
  342.     assert( ClassInvariant(This) );
  343.     assert( !This->OpenForRead && !This->OpenForWrite );
  344. }
  345.  
  346. Boolean SIOIsOpenForWrite( StandardIO This )
  347. {
  348.     INITIALIZE_CLASS;
  349.  
  350.     assert( ClassInvariant(This) );
  351.  
  352.     return This->OpenForWrite;
  353. }
  354.  
  355. Boolean SIOIsOpenForRead( StandardIO This )
  356. {
  357.     INITIALIZE_CLASS;
  358.  
  359.     assert( ClassInvariant(This) );
  360.  
  361.     return This->OpenForRead;
  362. }
  363.  
  364.  
  365. void SIOPrintf( StandardIO This, const char * FormatString, ... )
  366. {
  367.     VarBuf Buffer = VBCreate();
  368.     va_list ArgumentPointer;
  369.  
  370.     INITIALIZE_CLASS;
  371.  
  372.     assert( ClassInvariant(This) );
  373.     assert( This->OpenForWrite );
  374.  
  375.     va_start( ArgumentPointer, FormatString );
  376.  
  377.     VBPrintfVA( Buffer, FormatString, ArgumentPointer );
  378.  
  379.     if ( fprintf( This->File, "%s", VBAsString( Buffer ) ) == EOF )
  380.     {
  381.         fprintf( stderr, "Cannot write to " );
  382.         perror( VBAsString(This->FileName) );
  383.         exit( EXIT_FAILURE );
  384.     }
  385.  
  386.     va_end( ArgumenPointer );
  387.  
  388.     VBDestroy( Buffer );
  389. }
  390.  
  391. Boolean SIOEndOfFile( StandardIO This )
  392. {
  393.     INITIALIZE_CLASS;
  394.  
  395.     assert( ClassInvariant(This) );
  396.     assert( This->OpenForRead );
  397.  
  398.     return feof( This->File );
  399. }
  400.  
  401. void SIOFileGetPartOfLine( StandardIO This, char * Buffer, int Size )
  402. {
  403.     INITIALIZE_CLASS;
  404.  
  405.     assert( ClassInvariant(This) );
  406.     assert( This->OpenForRead );
  407.  
  408.     if ( fgets( Buffer, Size, This->File ) == NULL )
  409.     {
  410.         /* NULL from fgets() means EOF or error. */
  411.         if ( ferror( This->File ) )
  412.         {
  413.             fprintf( stderr, "Cannot read from " );
  414.             perror( VBAsString(This->FileName) );
  415.             exit(EXIT_FAILURE);
  416.         }
  417.     }
  418. }
  419.  
  420. void SIOPrintError( const char * Prefix )
  421. {
  422.     INITIALIZE_CLASS;
  423.  
  424.     assert( ClassInvariant(StandardError) );
  425.     assert( StandardError->OpenForWrite );
  426.  
  427.     perror( Prefix );
  428. }
  429.  
  430.  
  431. void SIOFlushBuffers( StandardIO This )
  432. {
  433.     INITIALIZE_CLASS;
  434.  
  435.     assert( ClassInvariant(This) );
  436.     assert( This->OpenForWrite );
  437.  
  438.     if ( fflush( This->File ) == EOF )
  439.     {
  440.         fprintf( stderr, "Cannot write to " );
  441.         perror( VBAsString(This->FileName) );
  442.         exit( EXIT_FAILURE );
  443.     }
  444. }
  445.  
  446.  
  447. void SIOInternetCommand( StandardIO This, const char * Command )
  448. {
  449.     INITIALIZE_CLASS;
  450.  
  451.     assert( ClassInvariant(This) );
  452.     assert( This->OpenForWrite );
  453.  
  454.     SIOPrintf( This, "%s\r\n", Command );
  455.     SIOFlushBuffers( This );
  456. }
  457.  
  458. int SIOFileDescriptor( StandardIO This )
  459. {
  460.     INITIALIZE_CLASS;
  461.  
  462.     assert( ClassInvariant(This) );
  463.     assert( This->File != NULL );
  464.  
  465.     return( fileno(This->File) );
  466. }
  467.  
  468. int SIORead( StandardIO This, void * Buffer, int BufferSize )
  469. {
  470.     size_t BytesRead;
  471.  
  472.     INITIALIZE_CLASS;
  473.  
  474.     assert( ClassInvariant(This) );
  475.     assert( This != NULL );
  476.     assert( SIOIsOpenForRead(This) );
  477.  
  478.     BytesRead = fread( Buffer, (size_t)1, (size_t)BufferSize, This->File );
  479.  
  480.     if ( BytesRead < 0 )
  481.     {
  482.     fprintf( stderr, "Error reading from " );
  483.     perror( VBAsString(This->FileName) );
  484.     exit(EXIT_FAILURE);
  485.     }
  486.  
  487.     return BytesRead;
  488. }
  489.  
  490. void SIOWrite( StandardIO This, void * Buffer, int BufferSize )
  491. {
  492.     int BytesWritten;;
  493.  
  494.     INITIALIZE_CLASS;
  495.  
  496.     assert( ClassInvariant(This) );
  497.  
  498.     BytesWritten = fwrite( Buffer, (size_t)1, (size_t)BufferSize, This->File );
  499.  
  500.     if ( BytesWritten != BufferSize )
  501.     {
  502.     fprintf( stderr, "Error writing to" );
  503.     perror( VBAsString(This->FileName) );
  504.     exit(EXIT_FAILURE);
  505.     }
  506. }
  507.